package com.virtualparadigm.compositor;

import java.io.Serializable;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;

import com.virtualparadigm.identity.Identifiable;
import com.virtualparadigm.identity.ResourceIdentifier;

public class OneToOneRequiredAggregatePart<ThisType extends Identifiable, ThatType  extends CompositePart<? extends Identifiable>> implements Serializable
{
	private static final long serialVersionUID = 1L;
	
	// Why need "wrapped" Aggregate instance?
	//   - b/c aggregate is implemented via composition
	private ThisType instance;
	private OneToOneRequiredAggregator<ThatType, ThisType> oneToOneRequiredAggregator;

	public OneToOneRequiredAggregatePart(ThisType instance, OneToOneRequiredAggregator<ThatType, ThisType> oneToOneAggregator) 
	{
		this.setInstance(instance);
		this.setOneToOneRequiredAggregator(oneToOneAggregator);
	}
	

	public ThisType getInstance()
	{
		return instance;
	}
	private void setInstance(ThisType instance)
	{
		this.instance = instance;
	}
	
	// package protected
	OneToOneRequiredAggregator<ThatType, ThisType> getOneToOneRequiredAggregator()
	{
		return this.oneToOneRequiredAggregator;
	}
	public ThatType getAggregate()
	{
		ThatType typedAggregator = null;
		OneToOneRequiredAggregator<ThatType, ThisType> oneToOneAggregator = this.getOneToOneRequiredAggregator();
		if(oneToOneAggregator != null)
		{
			typedAggregator = oneToOneAggregator.getInstance();
		}
		return typedAggregator;
	}
	
	// package protected
	boolean setOneToOneRequiredAggregator(OneToOneRequiredAggregator<ThatType, ThisType> oneToOneRequiredAggregator)
	{
		if(this.oneToOneRequiredAggregator == null)
		{
			if(oneToOneRequiredAggregator != null)
			{
				this.oneToOneRequiredAggregator = oneToOneRequiredAggregator;
				oneToOneRequiredAggregator.setOneToOneRequiredAggregatePart(this);
			}
		}
		else
		{
			if(!this.oneToOneRequiredAggregator.equals(oneToOneRequiredAggregator))
			{
				OneToOneRequiredAggregator<ThatType, ThisType> tempOneToOneAggregator = this.oneToOneRequiredAggregator;
				this.oneToOneRequiredAggregator = oneToOneRequiredAggregator;
				tempOneToOneAggregator.setOneToOneRequiredAggregatePart(null);
				if(oneToOneRequiredAggregator == null)
				{
					//since im required, tell the aggregator's compositor to remove the aggregator
					this.oneToOneRequiredAggregator.removeFromCompositor();
				}
				else
				{
					tempOneToOneAggregator.setOneToOneRequiredAggregatePart(this);
				}
			}
		}
		return true;
	}
	
	public boolean setAggregator(ThatType aggregator) 
	{
		OneToOneRequiredAggregator<ThatType, ThisType> oneToOneAggregator = null;
		if(aggregator != null)
		{
			oneToOneAggregator = new OneToOneRequiredAggregator<ThatType, ThisType>(aggregator, this);
		}
		return this.setOneToOneRequiredAggregator(oneToOneAggregator);
	}


	// ================================================
	// UTILITY METHODS
	// ================================================
	public String toString()
	{
//		return ReflectionToStringBuilder.toString(this, ToStringStyle.MULTI_LINE_STYLE);
		return ReflectionToStringBuilder.toString(this, ToStringStyleBuilder.toStringStyle);
	}
	public int hashCode()
	{
		HashCodeBuilder builder = new HashCodeBuilder();
	    builder.append(this.getInstance().getResourceIdentifier());
	    return builder.toHashCode();		
	}
	public boolean equals(Object obj)
	{
		if (obj == null)
		{
			return false;
		}
		if (obj == this)
		{
			return true;
		}
		if (obj.getClass() != getClass())
		{
			return false;
		}
		OneToOneRequiredAggregatePart<ThisType, ThatType> that = (OneToOneRequiredAggregatePart<ThisType, ThatType>)obj;
		EqualsBuilder builder = new EqualsBuilder();
	    builder.append(this.getInstance().getResourceIdentifier(), that.getInstance().getResourceIdentifier());
		return builder.isEquals();
	}
	
}